import path from 'path';
import turf from '../../../ext/turf';
import axios from 'axios';
import configTool from '../../../com/configTool';
import readFromDB from '../Util/readFromDB';
import readFromNet from '../Util/readFromNet';
import saveToDB from '../Util/saveToDB';
import saveToFile from '../Util/saveToFile';
import initDB from '../Util/initDB';
import awaitWrap from '../../../lib/awaitWrap';
import TileUtil4326 from '../../../lib/TileTool/TileUtil4326';
import TileSet from '../../TileTool/TileSet';
import readFromDisk from '../Util/readFromDisk';

const World = require('./World.json');

let authority_ing = false;
const DBName = 'CesiumWorldTerrain';
const baseUrl = 'https://assets.ion.cesium.com/asset_depot/1/CesiumWorldTerrain/v1.2/';
const ext = '?extensions=octvertexnormals-watermask-metadata&v=1.2.0';
const Cesium = require('cesium/Build/Cesium/index.cjs');
let Authorization = '';
const defaultAccessToken = Cesium.Ion.defaultAccessToken;

let CesiumTerrain = {
	async init() {
		await configTool.init();
		configTool.preservableONDB() && await initDB(DBName);
	},
	async ionAuthority() {
		if (authority_ing) {
			await new Promise((resolve) => {
				let timer = setInterval(() => {
					if (!authority_ing) {
						clearInterval(timer);
						resolve(null);
					}
				}, 100);
			});
		} else {
			authority_ing = true;
			let [err, data] = await awaitWrap(axios.get('https://api.cesium.com/v1/assets/1/endpoint?access_token=' + defaultAccessToken));
			if (data) {
				data = data.data;
				Authorization = 'Bearer ' + data.accessToken;
				console.log('获取令牌成功', data.accessToken);

			} else {
				console.log(Cesium.Ion.defaultAccessToken);
				console.log('获取令牌失败');
			}
			authority_ing = false;
		}
	},
	async getFileBuffer(url: string) {
		await this.init();

		let err, buffer, dataSource;
		let headers = {'Authorization': Authorization};

		let relativePath = '\\1\\' + url;
		let fileSavePath = path.join(configTool.appBasePath, `temp/fileOut/assets.cesium.com`, relativePath);

		// 从本地文件夹中获取文件
		[err, buffer, dataSource] = await readFromDisk({fileSavePath, err, buffer, dataSource});

		// 从数据库中获取文件
		[err, buffer, dataSource] = await readFromDB({DBName, relativePath, err, buffer, dataSource});

		// 从网络获取，并持久化存储
		if (!buffer) {
			// Authorization === '' && await this.ionAuthority();
			[err, buffer, dataSource] = await readFromNet({url: baseUrl + url + ext, headers, err, buffer, dataSource});
		}

		if (err?.state === 404) {
		} else if (err?.state === 503) {
			console.log('请求过于频繁，服务器拒绝响应');
		} else if (err?.state === 401) {
			console.log(err);
			console.log('重置 Cesium 地形资源的 令牌');
			Authorization = '';
		}

		buffer && dataSource !== 'DB' && configTool.preservableONDB() && saveToDB({
			DBName,
			relativePath,
			buffer
		}, true).then();
		buffer && dataSource === 'Net' && configTool.preservableONFile() && saveToFile(fileSavePath, buffer).then();

		return [err, buffer];
	},
	async getTileListByGeoJson(zoom: number, geoJson: any, layerJson: any) {
		await this.init();
		const tileUtil4326 = new TileUtil4326();

		geoJson = geoJson || World;

		if (!layerJson) {
			const [err, buffer] = await CesiumTerrain.getFileBuffer('layer.json');
			layerJson = buffer ? JSON.parse(buffer.toString()) : null;
			if (err || layerJson === null) {
				return {tileList: [], boxList: []};
			}
		}


		const dataRanges = layerJson.available;

		const tileSet = new TileSet();
		const boxList = [];
		const areaRangeList = dataRanges[zoom];
		const effectiveAreaRangeList = [];
		for (let i = 0; i < areaRangeList?.length; i++) {
			// 原始数据的边界范围
			const rowAreaRange = areaRangeList[i];

			const rowMinTile = tileUtil4326.tileXYZToRectanglePolygon(rowAreaRange.startX, rowAreaRange.startY, zoom);
			const rowMaxTile = tileUtil4326.tileXYZToRectanglePolygon(rowAreaRange.endX, rowAreaRange.endY, zoom);
			// 数据区
			const rowAreaBbox = turf.bbox(turf.featureCollection([rowMinTile, rowMaxTile]));
			const rowAreaBoxPolygon = turf.bboxPolygon(rowAreaBbox);


			if (turf.booleanDisjoint(geoJson, rowAreaBoxPolygon)) {
				continue;
			}

			// 裁切区
			const polygons: any = [];
			turf.featureEach(geoJson, function (currentFeature: any) {
				if (currentFeature.geometry.type === 'Polygon') {
					polygons.push(currentFeature.geometry.coordinates);
				}
			});

			const multiPoly = turf.multiPolygon(polygons);

			const clipGeoJson = turf.bboxClip(multiPoly, rowAreaBbox);
			const clipBbox = turf.bbox(clipGeoJson);

			const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
			const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);
			const trimRowAreaRange = {
				endX: Math.min(trimMaxTile.x, rowAreaRange.endX),
				endY: Math.min(trimMaxTile.y, rowAreaRange.endY),
				startX: Math.max(trimMinTile.x, rowAreaRange.startX),
				startY: Math.max(trimMinTile.y, rowAreaRange.startY)
			};

			// 将原始边界拆分为四份
			// const middleX = rowAreaRange.startX + Math.floor((rowAreaRange.endX - rowAreaRange.startX) / 2) - 1;
			// const middleY = rowAreaRange.startY + Math.floor((rowAreaRange.endY - rowAreaRange.startY) / 2) - 1;

			// const leafLeftTop = {startX: rowAreaRange.startX, startY: rowAreaRange.startY, endX: middleX, endY: middleY}
			// const leafRightTop = {startX: middleX + 1, startY: rowAreaRange.startY, endX: rowAreaRange.endX, endY: middleY}
			// const leafLeftBottom = {startX: rowAreaRange.startX, startY: middleY + 1, endX: middleX, endY: rowAreaRange.endY}
			// const leafRightBottom = {startX: middleX + 1, startY: middleY + 1, endX: rowAreaRange.endX, endY: rowAreaRange.endY}

			// const leafList = [leafLeftTop, leafRightTop, leafLeftBottom, leafRightBottom];


			// 将原始边界拆分为 3X3 的 九 份
			const middle_1_3_X = trimRowAreaRange.startX + Math.floor((trimRowAreaRange.endX - trimRowAreaRange.startX) / 3) - 1;
			const middle_2_3_X = trimRowAreaRange.startX + Math.floor((trimRowAreaRange.endX - trimRowAreaRange.startX) / 3) * 2 - 1;
			const middle_1_3_Y = trimRowAreaRange.startY + Math.floor((trimRowAreaRange.endY - trimRowAreaRange.startY) / 3) - 1;
			const middle_2_3_Y = trimRowAreaRange.startY + Math.floor((trimRowAreaRange.endY - trimRowAreaRange.startY) / 3) * 2 - 1;

			const leafOne = {
				startX: trimRowAreaRange.startX,
				startY: trimRowAreaRange.startY,
				endX: middle_1_3_X,
				endY: middle_1_3_Y
			};
			const leafTwo = {
				startX: middle_1_3_X + 1,
				startY: trimRowAreaRange.startY,
				endX: middle_2_3_X,
				endY: middle_1_3_Y
			};
			const leafThree = {
				startX: trimRowAreaRange.startX,
				startY: middle_1_3_Y + 1,
				endX: middle_1_3_X,
				endY: middle_2_3_Y
			};
			const leafFour = {
				startX: middle_1_3_X + 1,
				startY: middle_1_3_Y + 1,
				endX: middle_2_3_X,
				endY: middle_2_3_Y
			};
			const leafFive = {
				startX: middle_2_3_X + 1,
				startY: trimRowAreaRange.startY,
				endX: trimRowAreaRange.endX,
				endY: middle_1_3_Y
			};
			const leafSix = {
				startX: middle_2_3_X + 1,
				startY: middle_1_3_Y + 1,
				endX: trimRowAreaRange.endX,
				endY: middle_2_3_Y
			};
			const leafSeven = {
				startX: trimRowAreaRange.startX,
				startY: middle_2_3_Y + 1,
				endX: middle_1_3_X,
				endY: trimRowAreaRange.endY
			};
			const leafEight = {
				startX: middle_2_3_X + 1,
				startY: middle_2_3_Y + 1,
				endX: trimRowAreaRange.endX,
				endY: trimRowAreaRange.endY
			};
			const leafNine = {
				startX: middle_1_3_X + 1,
				startY: middle_2_3_Y + 1,
				endX: middle_2_3_X,
				endY: trimRowAreaRange.endY
			};
			const leafList = [leafOne, leafTwo, leafThree, leafFour, leafFive, leafSix, leafSeven, leafEight, leafNine];


			for (let j = 0; j < leafList.length; j++) {
				const leafAreaRange = leafList[j];

				const minTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.startX, leafAreaRange.startY, zoom);
				const maxTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.endX, leafAreaRange.endY, zoom);
				// 数据区
				const areaBbox = turf.bbox(turf.featureCollection([minTile, maxTile]));
				const areaBoxPolygon = turf.bboxPolygon(areaBbox);

				if (!turf.booleanDisjoint(geoJson, areaBoxPolygon)) {

					// 裁切区
					const polygons: any = [];
					turf.featureEach(geoJson, function (currentFeature: any) {
						if (currentFeature.geometry.type === 'Polygon') {
							polygons.push(currentFeature.geometry.coordinates);
						}
					});

					const multiPoly = turf.multiPolygon(polygons);

					const clipGeoJson = turf.bboxClip(multiPoly, areaBbox);
					const clipBbox = turf.bbox(clipGeoJson);

					const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
					const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);

					const areaRange = {
						endX: Math.min(trimMaxTile.x, leafAreaRange.endX),
						endY: Math.min(trimMaxTile.y, leafAreaRange.endY),
						startX: Math.max(trimMinTile.x, leafAreaRange.startX),
						startY: Math.max(trimMinTile.y, leafAreaRange.startY)
					};
					// const areaRange = leafAreaRange;

					const areaRangeBox = turf.bboxPolygon(
						turf.bbox(
							turf.featureCollection(
								[
									tileUtil4326.tileXYZToRectanglePolygon(areaRange.startX, areaRange.startY, zoom),
									tileUtil4326.tileXYZToRectanglePolygon(areaRange.endX, areaRange.endY, zoom)
								]
							)
						)
					);

					boxList.push(areaRangeBox);
					effectiveAreaRangeList.push(areaRange);
					for (let x = areaRange.startX; x <= areaRange.endX; x++) {
						for (let y = areaRange.startY; y <= areaRange.endY; y++) {
							tileSet.add(x, y, zoom);
						}
					}
				}
			}

		}


		return {tileList: tileSet.getAll(), boxList, effectiveAreaRangeList};
	}
};


export default CesiumTerrain;

